﻿// -----------------------------------------------------------------------
// Copyright (c) David Kean. All rights reserved.
// -----------------------------------------------------------------------
extern alias pcl;
using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebUtility = pcl::System.Net.WebUtility;
using SystemWebUtility = System.Net.WebUtility;

namespace Portable.Net
{
    [TestClass]
    public class WebUtilityTests
    {
        [TestMethod]
        public void HtmlEncode1_NullAsValue_ReturnsNull()
        {
            var result = WebUtility.HtmlEncode(null);

            Assert.IsNull(result);
        }

        [TestMethod]
        public void HtmlDecode2_NullAsValue_ReturnsNull()
        {
            var result = WebUtility.HtmlDecode(null);

            Assert.IsNull(result);
        }

        [TestMethod]
        public void HtmlEncode2_NullAsValue_DoesNotWriteToOutput()
        {
            var result = new StringWriter();

            WebUtility.HtmlEncode((string)null, result);

            Assert.AreEqual(string.Empty, result.ToString());
        }

        [TestMethod]
        public void HtmlDecode2_NullAsValue_DoesNotWriteToOutput()
        {
            var result = new StringWriter();

            WebUtility.HtmlDecode((string)null, result);

            Assert.AreEqual(string.Empty, result.ToString());
        }
        
        [TestMethod]
        public void HtmlEncode1_EmptyAsValue_ReturnsEmpty()
        {
            var result = WebUtility.HtmlEncode(string.Empty);

            Assert.AreEqual(string.Empty, result);
        }

        [TestMethod]
        public void HtmlDecode1_EmptyAsValue_ReturnsEmpty()
        {
            var result = WebUtility.HtmlDecode(string.Empty);

            Assert.AreEqual(string.Empty, result);
        }

        [TestMethod]
        public void HtmlEncode2_EmptyAsValue_DoesNotWriteToOutput()
        {
            var result = new StringWriter();

            WebUtility.HtmlEncode(string.Empty, result);

            Assert.AreEqual(string.Empty, result.ToString());
        }


        [TestMethod]
        public void HtmlDecode2_EmptyAsValue_DoesNotWriteToOutput()
        {
            var result = new StringWriter();

            WebUtility.HtmlDecode(string.Empty, result);

            Assert.AreEqual(string.Empty, result.ToString());
        }

        [TestMethod]
        public void HtmlEncode2_WhenValueIsNull_NullAsOutput_DoesNotThrow()
        {
            WebUtility.HtmlEncode((string)null, (TextWriter)null);
        }

        [TestMethod]
        public void HtmlDecode2_WhenValueIsNull_NullAsOutput_DoesNotThrow()
        {
            WebUtility.HtmlDecode((string)null, (TextWriter)null);
        }

        [TestMethod]
        public void HtmlEncode2_WhenValueIsNotNull_NullAsOutput_ThrowsArgumentNull()
        {
            ExceptionAssert.ThrowsArgumentNull("output", () =>
            {
                WebUtility.HtmlEncode(string.Empty, (TextWriter)null);
            });
        }

        [TestMethod]
        public void HtmlDecode2_WhenValueIsNotNull_NullAsOutput_ThrowsArgumentNull()
        {
            ExceptionAssert.ThrowsArgumentNull("output", () =>
            {
                WebUtility.HtmlDecode(string.Empty, (TextWriter)null);
            });
        }

        [TestMethod]
        public void HtmlEncode1_ValueContainingSpecialChars_AreEncoded()
        {
            var inputs = new [] { 
                Tuple.Create("\x00a0", "&#160;"), 
                Tuple.Create("\x00a1", "&#161;"), 
                Tuple.Create("\x00DD", "&#221;"), 
                Tuple.Create("\x00FE", "&#254;"), 
                Tuple.Create("\x00FF", "&#255;"), 
                Tuple.Create("&", "&amp;"), 
                Tuple.Create("&&", "&amp;&amp;"), 
                Tuple.Create("\"", "&quot;"), 
                Tuple.Create("&\"", "&amp;&quot;"), 
                Tuple.Create("<", "&lt;"), 
                Tuple.Create(">", "&gt;"), 
                Tuple.Create("'", "&#39;"), 
                Tuple.Create(" '", " &#39;"), 
                Tuple.Create("The quick brown fox&jumped over the lazy dog", "The quick brown fox&amp;jumped over the lazy dog"), 
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlEncode(input.Item1);

                Assert.AreEqual(input.Item2, result);
                Assert.AreEqual(input.Item2, SystemWebUtility.HtmlEncode(input.Item1));
            }
        }

        [TestMethod]
        public void HtmlEncode1_ValueContainingNormalChars_AreNotEncoded()
        {
            var inputs = new [] { 
                " ",
                "\x009F",
                "\x0100",
                "\xFFFF",
                "\xFFFF",
                "♠",
                "™",
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlEncode(input);

                Assert.AreEqual(input, result);
                Assert.AreEqual(input, SystemWebUtility.HtmlEncode(input));
            }
        }

        [TestMethod]
        public void HtmlDecode1_ValueContainingHexEntity_AreDecoded()
        {
            var inputs = new[] { 
                Tuple.Create("&#xa0;",   "\x00a0"),
                Tuple.Create("&#xa;",    "\x000a"),
                Tuple.Create("&#x00a0;", "\x00a0"), 
                Tuple.Create("&#X00a0;", "\x00a0"), 
                Tuple.Create("&#xFFFF;", "\xFFFF"), 
                Tuple.Create("&#x00FF;", "\x00FF"), 
                Tuple.Create("&#x0000000FF;", "\x00FF"), 
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlDecode(input.Item1);

                Assert.AreEqual(input.Item2, result);
                Assert.AreEqual(input.Item2, SystemWebUtility.HtmlDecode(input.Item1));
            }
        }

        [TestMethod]
        public void HtmlDecode1_ValueContainingDecimalEntity_AreDecoded()
        {
            var inputs = new[] { 
                Tuple.Create("&#160;",   "\x00a0"),
                Tuple.Create("&#10;",    "\x000a"),
                Tuple.Create("&#00160;", "\x00a0"), 
                Tuple.Create("&#0010;", "\x000a"), 
                Tuple.Create("&#65535;", "\xFFFF"), 
                Tuple.Create("&#255;", "\x00FF"), 
                Tuple.Create("&# 255;", "\x00FF"), 
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlDecode(input.Item1);

                Assert.AreEqual(input.Item2, result);
                Assert.AreEqual(input.Item2, SystemWebUtility.HtmlDecode(input.Item1));
            }
        }

        [TestMethod]
        public void HtmlDecode1_ValueContainingTextEntity_AreDecoded()
        {
            var inputs = new[] { 
                Tuple.Create("&diams;", "♦"),
                Tuple.Create("&nsub;",  "⊄"),
                Tuple.Create("&amp;",   "&"), 
                Tuple.Create("&lt;",    "<"), 
                Tuple.Create("&quot;",  "\""), 
                Tuple.Create("&apos;",  "'"), 
                Tuple.Create("&&amp;",   "&&"), 
                Tuple.Create(";&&amp;",   ";&&"), 
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlDecode(input.Item1);

                Assert.AreEqual(input.Item2, result);
                Assert.AreEqual(input.Item2, SystemWebUtility.HtmlDecode(input.Item1));
            }
        }

        [TestMethod]
        public void HtmlDecode1_ValueContainingUnformedEntities_AreNotDecoded()
        {
            var inputs = new[] { 
                Tuple.Create(" ", " "), 
                Tuple.Create("  ", "  "), 
                Tuple.Create("abc", "abc"), 
                Tuple.Create("123", "123"), 
                Tuple.Create("&&", "&&"), 
                Tuple.Create("&;", "&;"), 
                Tuple.Create("&&;", "&&;"), 
                Tuple.Create("&;&;", "&;&;"), 
                Tuple.Create("&unfinishedentity", "&unfinishedentity"), 
                Tuple.Create("&unknownentity;", "&unknownentity;"), 
                Tuple.Create("&#;", "&#;"), 
                Tuple.Create("&#invalidnumericentity;", "&#invalidnumericentity;"), 
                Tuple.Create("&#Xinvalidhexentity;", "&#Xinvalidhexentity;"), 
                Tuple.Create("&#xinvalidhexentity;", "&#xinvalidhexentity;"), 
                Tuple.Create("&#65536;", "&#65536;"),   // unshort.MaxValue + 1
                Tuple.Create("&#-65535;", "&#-65535;"), 
                Tuple.Create("&#x10000;", "&#x10000;"), 
                Tuple.Create("abc&123", "abc&123"), 
                Tuple.Create("abc&unknownentity;", "abc&unknownentity;"), 
                Tuple.Create("abc&#invalidentity;", "abc&#invalidentity;"), 
                Tuple.Create("&#x 00FF;", "&#x 00FF;"), 
            };

            foreach (var input in inputs)
            {
                var result = WebUtility.HtmlDecode(input.Item1);

                Assert.AreEqual(input.Item2, result);
                Assert.AreEqual(input.Item2, SystemWebUtility.HtmlDecode(input.Item1));
            }
        }

        
    }
}
